﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using StackExchange.Redis;

namespace Sunny.Service
{
    public class RedisService
    {
        private class RedisConfig
        {
            public string Host { get; set; }
            public int Port { get; set; }
            public string UserName{get;set;}
            public string Password { get; set; }
        }
        
        private IDatabase redis;
        public IServer server;
        public RedisService(IConfiguration configuration)
        {
            var redisConfig = configuration.GetSection("Redis").Get<RedisConfig>();
            ConfigurationOptions options = new ConfigurationOptions();
            options.User = redisConfig.UserName;
            options.Password = redisConfig.Password;
            options.AllowAdmin = true;
            options.AsyncTimeout = 100000;
            options.ConnectTimeout = 100000;
            options.ResponseTimeout = 100000;
            options.SyncTimeout = 100000;
            options.EndPoints.Add(redisConfig.Host,redisConfig.Port);
            ConnectionMultiplexer connectionMultiplexer = ConnectionMultiplexer.Connect(options);
            redis = connectionMultiplexer.GetDatabase(0);
            server = connectionMultiplexer.GetServer(connectionMultiplexer.GetEndPoints()[0]);
        }
        
        [Obsolete(message:"尽量不要使用此方式操作redis,建议二次封装方法")]
        public IDatabase RedisInstance => redis;

        #region 设置redis值
        /// <summary>
        /// 设置redis值
        /// </summary>
        /// <param name="redisKeyPrefix"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <typeparam name="T"></typeparam>

        public void Set<T>(AbstractRedisKeyPrefix redisKeyPrefix,string key,T value)
        {
            string realKey = redisKeyPrefix.KeyPrefix+":"+key;
            string realValue = JsonConvert.SerializeObject(value);
            redis.StringSet(realKey,realValue,TimeSpan.FromSeconds(redisKeyPrefix.Expire));
        }

        #endregion

        #region 获取redis值
        /// <summary>
        /// 获取redis值
        /// </summary>
        /// <param name="redisKeyPrefix"></param>
        /// <param name="key"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T Get<T>(AbstractRedisKeyPrefix redisKeyPrefix,string key)
        {
            string realKey = redisKeyPrefix.KeyPrefix+":"+key;
            var redisValue = redis.StringGet(realKey);
            if(string.IsNullOrEmpty(redisValue))
            {
                return default(T);
            }
            var obj = JsonConvert.DeserializeObject(redisValue,typeof(T));
            return (T)obj;
        }

        #endregion
        
        #region 获取redis值
        /// <summary>
        /// 获取redis值
        /// </summary>
        /// <param name="key"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T Get<T>(string key)
        {
            var redisValue = redis.StringGet(key);
            if(string.IsNullOrEmpty(redisValue))
            {
                return default(T);
            }
            var obj = JsonConvert.DeserializeObject(redisValue,typeof(T));
            return (T)obj;
        }

        #endregion

        #region 判断key是否存在
        /// <summary>
        /// 判断key是否存在
        /// </summary>
        /// <param name="redisKeyPrefix"></param>
        /// <param name="key"></param>
        /// <returns></returns>

        public bool KeyExists(AbstractRedisKeyPrefix redisKeyPrefix,string key)
        {
            string realKey = redisKeyPrefix.KeyPrefix+":"+key;
            return redis.KeyExists(realKey);
        }

        #endregion

        #region 增加值并返回增加后的值
        /// <summary>
        /// 增加值并返回增加后的值
        /// </summary>
        /// <param name="redisKeyPrefix"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>

        public long Incr(AbstractRedisKeyPrefix redisKeyPrefix,string key,long value = 1)
        {
            string realKey = redisKeyPrefix.KeyPrefix+":"+key;
            return redis.StringIncrement(realKey,value);
        }

        #endregion
        
        #region 减少值并返回增加后的值
        /// <summary>
        /// 减少值并返回增加后的值
        /// </summary>
        /// <param name="redisKeyPrefix"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>

        public long Decr(AbstractRedisKeyPrefix redisKeyPrefix,string key,long value = 1)
        {
            string realKey = redisKeyPrefix.KeyPrefix+":"+key;
            return redis.StringDecrement(realKey,value);
        }

        #endregion

        #region 删除一个key
        
        public bool DeleteKey(AbstractRedisKeyPrefix redisKeyPrefix,string key)
        {
            string realKey = redisKeyPrefix.KeyPrefix+":"+key;
            return redis.KeyDelete(realKey);
        }

        #endregion

        #region 设置一个key的过期时间

        public bool SetEx(AbstractRedisKeyPrefix prefix,string key)
        {
            string realKey = prefix.KeyPrefix+":"+key;
            return redis.KeyExpire(realKey,TimeSpan.FromSeconds(prefix.Expire));
        }

        #endregion

        #region 获取所有key

        public List<string> Keys(AbstractRedisKeyPrefix keyPrefix,string key)
        {
            string realKey = keyPrefix.KeyPrefix+":"+key;
            var redisKeys = server.Keys(0,realKey);
            List<string> keys = new List<string>();
            foreach (var redisKey in redisKeys)
            {
                keys.Add((string)redisKey);
            }
            
            return keys;
        }

        #endregion
    }
}